/*
 * Lambda.cpp
 *
 *  Created on: 17/nov/2010
 *      Author: computer
 */

#include "Lambda.h"
#include "FlowExpression.h"
#include "Null.h"
#include "TemplatePattern.cpp" //TODO warning

namespace TreeExpression {

Lambda::Lambda(const std::string& _nameLambda) : Expression_CRTP<Lambda>(), Functor(_nameLambda) { }

Lambda::Lambda(const Lambda& copy) : Expression(copy), FlowExpression(copy), Expression_CRTP<Lambda>(copy), Functor(copy), listInstruction(copy.listInstruction) { }

Lambda::~Lambda() { }

AutoPointer<Expression> Lambda::eval(CopyPointer<Context>& context) {
	//TODO Modificare contesto
	//TODO distruggere variabili locali
	//TODO copiare le istruzioni
	CopyPointer<Context> localContext(new Context(context.get(), this->getName()));
	std::list< Pattern<> >::iterator j;
	AutoPointer<Expression> parameter(this->getSon());//Set the first parameter
	if (!this->getPattern().empty()) {
		std::list< Pattern<> > listPattern = this->getPattern();
		for (j = listPattern.begin(); j != listPattern.end(); ++j) {
			j->set(parameter, localContext);
			parameter = parameter->getLeaf();//Set the parameter
		}
	}
	std::list< AutoPointer<Expression> >::iterator i;
	for (i = listInstruction.begin(); i != listInstruction.end(); ++i) {
		FlowExpression* instruction = dynamic_cast<FlowExpression*>(i->get());
		if (instruction) {
			AutoPointer<Expression> ris = instruction->eval(localContext);
			if (instruction->isStop()) {//If it is a stop instruction (i.e.: return)
				if (ris->hasSon()) return ris->getSon();
				else return AutoPointer<TreeExpression::Expression>(new TreeExpression::Null());
			}
		}
		else {
			(*i)->eval(localContext);
		}
	}
	return AutoPointer<TreeExpression::Expression>(new TreeExpression::Null());
}

Expression* Lambda::clone() const {
	Lambda* ris = new Lambda(this->getName());
	std::list< AutoPointer<Expression> >::const_iterator i;
	for (i = listInstruction.begin(); i != listInstruction.end(); ++i) {
		ris->addInstruction(AutoPointer<Expression>((*i)->cloneTree()));
	}
	ris->setPattern(this->getPattern());
	return ris;
}

void Lambda::addInstruction(const AutoPointer<Expression>& instruction) {
	listInstruction.push_back(instruction);
}

}
